import puppeteer from "../../../lib/puppeteer/puppeteer.js"
import fetch from "node-fetch"
import moment from "moment"
import lodash from "lodash"
import fs from "fs"
import base from "./base.js"

if (!fs.existsSync("./data/payLog/")) {
  fs.mkdirSync("./data/payLog/")
}

export class PayData {
  constructor(authKey = "") {
    this.#authkey = encodeURIComponent(authKey)
  }

  #genShinId = ""
  #oringinData = []
  #authkey = ""

  /** 获取原始支付数据 */
  async getOringinalData(id = "") {
    let res = await fetch(this.getUrl() + id, this.headers)
    let ret = await res.json()
    let check = this.checkResult(ret)
    if (check?.errorMsg) return check
    let list = ret?.data?.list
    if (!Array.isArray(list)) {
      console.error(ret)
      return { errorMsg: "获取失败，错误码：" + ret?.retcode }
    }
    if (list.length === 20) {
      this.#oringinData.push(...list)
      await this.getOringinalData(list[19].id)
      return true
    } else {
      this.#oringinData.push(...list)
      return true
    }
  }

  /** 获取大月卡数据 */
  async getPrimogemLog(id = "") {
    let res = await fetch(this.getUrl("getPrimogemLog") + id, this.headers)
    let ret = await res.json()
    let check = this.checkResult(ret)
    if (check?.errorMsg) return check
    let list = ret?.data?.list
    if (!Array.isArray(list)) {
      console.error(ret)
      return { errorMsg: "获取失败，错误码：" + ret?.retcode }
    }
    if (list.length === 20) {
      list.forEach(v => {
        if (v.add_num === "680") this.#oringinData.push(v)
      })
      await this.getPrimogemLog(list[19].id)
      return true
    } else {
      list.forEach(v => {
        if (v.add_num === "680") this.#oringinData.push(v)
      })
      return true
    }
  }

  async getUserInfo() {
    let res = await fetch(this.getUrl("getUserInfo"), this.headers)
    let ret = await res.json()
    let check = this.checkResult(ret)
    if (check?.errorMsg) return check
    let data = ret?.data
    if (data?.uid) {
      return data
    }
    return { errorMsg: "获取失败，可能是链接已过期或不正确" }
  }

  checkResult(ret) {
    if (ret?.retcode === -101 || ret?.retcode === -100) {
      return ret.retcode === -101
        ? { errorMsg: "您的链接过期，请重新获取" }
        : { errorMsg: "链接不正确，请重新获取" }
    }
    if (/unknown auth appid/.test(ret?.message)) {
      return { errorMsg: "抽卡或其他链接现已无法获取充值记录，请发送客服页面的链接！" }
    }
    return { errorMsg: "" }
  }

  /** 对原始数据进行筛选，组合 */
  async filtrateData() {
    // 由于新接口不返回uid了，所以先查询出用户信息
    const userInfo = await this.getUserInfo()
    if (userInfo?.errorMsg) return userInfo
    this.#genShinId = userInfo.uid
    // 获取数据
    let isSucceed = await this.getOringinalData()
    // 判断数据是否获取成功
    if (isSucceed?.errorMsg) return isSucceed
    await this.getPrimogemLog()
    // 判断零氪党的情况
    if (this.#oringinData.length === 0) {
      return { errorMsg: "未获取到您的任何充值数据" }
    }
    // 将原始数据按id排序
    this.#oringinData = this.#oringinData.sort((a, b) => {
      let val1 = Number(a.id)
      let val2 = Number(b.id)
      if (val2 > val1) {
        return -1
      } else {
        return 1
      }
    })
    // 单双倍结晶数
    const price = [680, 300, 8080, 3880, 2240, 1090, 330, 60]
    const doublePrice = [0, 0, 12960, 6560, 3960, 1960, 600, 120]
    let month = 0
    let sum = 0
    let i = -1
    let listIndex = 0
    let list = []
    for (let index = 0; index < this.#oringinData.length; index++) {
      // 如果小于零则返回
      let num = Number(this.#oringinData[index].add_num)
      if (num < 0) continue
      // 获取月份
      // let thisMonth = ++moment(this.#oringinData[index].time).toArray()[1]
      // 新接口改名为：datetime
      let thisMonth = ++moment(this.#oringinData[index].datetime).toArray()[1]
      if (thisMonth !== month) {
        i++
        month = thisMonth
        list[listIndex++] = {
          month: thisMonth + "月",
          payNum: [0, 0, 0, 0, 0, 0, 0, 0],
        }
      } else if (!i) {
        list[i] = {
          month: thisMonth + "月",
          payNum: [0, 0, 0, 0, 0, 0, 0, 0],
        }
      }
      for (let index = 0; index < 8; index++) {
        if (num === price[index] || num === doublePrice[index]) {
          list[i].payNum[index]++
          if (num !== 680) sum += num
          break
        }
      }
    }
    return {
      uid: this.#genShinId,
      crystal: sum,
      monthData: list,
    }
  }

  headers = {
    headers: {
      accept: "application/json, text/plain, */*",
      "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
      "sec-fetch-dest": "empty",
      "sec-fetch-mode": "cors",
      "sec-fetch-site": "same-site",
    },
    referrer: "https://webstatic.mihoyo.com/",
    referrerPolicy: "strict-origin-when-cross-origin",
    method: "GET",
    mode: "cors",
    credentials: "include",
  }

  /**
   * 获取url
   * @param api 原石 getPrimogemLog // 结晶 getCrystalLog // 获取用户信息 getUserInfo
   * @returns {string}
   */
  getUrl(api = "getCrystalLog") {
    const baseUrl = "https://hk4e-api.mihoyo.com/common/hk4e_self_help_query/User"
    const isUserInfo = api === "getUserInfo",
      isCrystalLog = api === "getCrystalLog"
    const url = isUserInfo ? "/GetUserInfo" : isCrystalLog ? "/GetCrystalLog" : "/GetPrimogemLog"
    let params = ""
    params += "?selfquery_type=1"
    params += "&sign_type=2"
    params += "&auth_appid=csc"
    params += "&authkey_ver=1"
    params += "&game_biz=hk4e_cn"
    params += "&win_direction=portrait"
    params += "&bbs_auth_required=true"
    params += "&bbs_game_role_required=hk4e_cn"
    params += "&app_client=bbs"
    params += "&lang=zh-cn"
    params += "&csc_authkey_required=true"
    params += "&authkey=" + this.#authkey
    params += "&page_id=1"
    // 此条件限定只查询获取的
    if (!isUserInfo) {
      params += "&add_type=produce"
      params += "&size=20"
      // endId，外部拼接
      params += "&end_id="
    }
    return baseUrl + url + params
    // 老API：
    // let type = api === 'getCrystalLog' ? 3 : 1
    // return `https://hk4e-api.mihoyo.com/ysulog/api/${api}?selfquery_type=${type}&lang=zh-cn&sign_type=2&auth_appid=csc&authkey_ver=1&authkey=${this.#authkey}&game_biz=hk4e_cn&app_client=bbs&type=${type}&size=20&end_id=`
  }
}

export class HtmlData extends base {
  /**
   * @param data 数据
   * @param data.monthData 月份数据
   * @param data.crystal 总结晶数
   */
  constructor(data = {}) {
    super()
    this.monthData = data.monthData
    this.crystal = data.crystal
    this.uid = data.uid
    this.model = "payLog"
  }

  crystal = 0
  uid = ""
  monthData = []

  // 价格
  price = [68, 30, 648, 328, 198, 98, 30, 6]

  /** 柱形图数据 */
  getBarData() {
    return this.monthData.map(v => {
      return {
        type: v.month,
        sales: v.payNum.reduce((sum, val, index) => sum + val * this.price[index], 0),
      }
    })
  }

  /** 顶部数据 */
  getTopData(crystal = 0) {
    const maxMonth = this.maxcConsumption()
    const sum = this.sumConsumption()
    return [
      {
        title: "总消费",
        value: "￥" + this.getBarData().reduce((sum, val) => sum + val.sales, 0),
      },
      {
        title: "总结晶",
        value: this.crystal,
      },
      {
        title: "消费最多",
        value: maxMonth.type,
      },
      {
        title: maxMonth.type + "消费",
        value: "￥" + maxMonth.sales,
      },
      ...sum,
    ]
  }

  /** 饼图数据 */
  getPieData() {
    const data = this.sumConsumption()
    let pieData = []
    data.forEach((val, index) => {
      let value = val.value * this.price[index]
      if (value) {
        pieData.push({
          value,
          name: val.title,
        })
      }
    })
    return pieData
  }

  /** 消费最多月 */
  maxcConsumption() {
    return this.getBarData().sort((a, b) => {
      if (a.sales < b.sales) {
        return 1
      } else {
        return -1
      }
    })[0]
  }

  /** 每种消费的总数 */
  sumConsumption() {
    let sum = {
      小月卡: 0,
      大月卡: 0,
      648: 0,
      328: 0,
      198: 0,
      98: 0,
      30: 0,
      6: 0,
    }
    // 循环sum,按照月份统计各个充值的类别总数
    let k = Object.keys(sum).reverse()
    this.monthData.forEach(val => {
      val.payNum.forEach((v, i) => {
        sum[k[i]] += v
      })
    })
    // 返回title,value对象'648':123456
    let value = Object.values(sum).reverse()
    return k.map((val, index) => {
      return {
        title: val,
        value: value[index],
      }
    })
  }
}

export async function renderImg(data) {
  const htmlData = new HtmlData(data)
  const imgDatas = {
    ...htmlData.screenData,
    topData: htmlData.getTopData(),
    barData: JSON.stringify(htmlData.getBarData()),
    pieData: JSON.stringify(htmlData.getPieData()),
    saveId: htmlData.uid,
    uid: htmlData.uid,
  }
  let img = await puppeteer.screenshot("payLog", imgDatas)
  return img
}
